#include "tests.h"
#include <stdlib.h>
#include <assert.h>
uthread_mutex_t mutex;
thread_id arr[3];

uthread_mutex_t print_mutex;
static void print_to_screen(char* str)
{
	int count = 0,writed = 0;
	int len = strlen(str);
	while (count != len) {
		writed = uthread_write(1,str+count,sizeof(char)*(len-count));
		if (writed	>=	0)
			count += writed;
	}
	return;
}

static char* itoa(int num)
{
	if	(num == 0) 
		return "0";
	int num_digits=0,i=1;
	while (i <= num) {
		num_digits++;
		i *= 10;
	}
	char* str = (char*)malloc((num_digits+1)*sizeof(char));
	char tmp;
	str[num_digits] = '\0';
	for (i = (num_digits-1); i >= 0; i--){
		tmp = (char)(num % 10) + '0';
		num /= 10;
		str[i] = tmp;
	}
	return str;
}

static void block(uthread_mutex_t mutex) 
{
	if (uthread_mutex_lock(mutex) != MUTEX_SUCCESS) {
		print_to_screen("Unable to lock mutex.\n");
		exit(-1);
	}
}

static void unblock(uthread_mutex_t mutex) 
{
	if (uthread_mutex_unlock(mutex) != MUTEX_SUCCESS) {
		print_to_screen("Unable to unlock mutex.\n");
		exit(-1);
	}
}

static inline void delay(int n, char c) {
	int i;
	for (i = 0 ; i < n ; i++)
		i=i;
}

static inline void reset_counter()
{
	counter = 0;
}

static void msg_with_expected_order(int i, char * in, int id){
		block(print_mutex);
		print_to_screen(itoa(i));
	  print_to_screen(": ");
		print_to_screen("Thread Id= ");
		print_to_screen(itoa(id));
		print_to_screen("   ");
		print_to_screen(in);
		print_to_screen("\n");
		unblock(print_mutex);
}

static void msg(char * in){
	msg_with_expected_order(1,in,uthread_self());
}

static int fff(void* y) {
int i,j;
if(uthread_self()!=2){
	for(i=0;i<1000000;i++){
		for(j=0;j<1000;j++);
	}
}
msg("my id is \n");
return uthread_self();
}

int start_routine(void* args)
{	
	int i,res;
	int arg = (int)args;
	if (arg == 0){
		print_to_screen("thread 1 running....\n");
		print_to_screen("thread 1 lock mutex....");
		res = uthread_mutex_lock(mutex);
		if (res == MUTEX_SUCCESS)
		print_to_screen("OK\n");
		else print_to_screen("someting wrong\n");
		print_to_screen("thread 1 lock again the mutex....");
		res = uthread_mutex_lock(mutex);
		if (res == MUTEX_FAILURE)
			print_to_screen("OK\n");
		else print_to_screen("someting wrong\n");
		for (i=0;i<100;i++){}
		uthread_yield();
		print_to_screen("thread 1 continue running....\n");
		print_to_screen("thread 1 unlock the mutex....");
		res = uthread_mutex_unlock(mutex);
		if (res == MUTEX_SUCCESS)
			print_to_screen("OK\n");
		else print_to_screen("someting wrong\n");
		print_to_screen("thread 1 finished....\n");
	}
	if (arg == 1){
		print_to_screen("thread 2 running....\n");
		print_to_screen("thread 2 lock mutex that locked by another thread,go to wait....\n");
		res = uthread_mutex_lock(mutex);
		print_to_screen("thread 2 continue running....");
		if (res == MUTEX_SUCCESS)
			print_to_screen("OK\n");
		else print_to_screen("someting wrong\n");
		for (i=0;i<100;i++){}
		print_to_screen("thread 2 unlock mutex.....");
		res = uthread_mutex_unlock(mutex);
		if (res == MUTEX_SUCCESS)
			print_to_screen("OK\n");
		else print_to_screen("someting wrong\n");
		print_to_screen("thread 2 finished....\n");
	}
	if (arg == 2){
		print_to_screen("thread 3 running....\n");
		print_to_screen("thread 3 try lock mutex that locked....");
		res = uthread_mutex_try_lock(mutex);
		if (res == MUTEX_LOCKED)
			print_to_screen("OK\n");
		else print_to_screen("someting wrong\n");
		for (i=0;i<100;i++){}
		print_to_screen("thread 3  unlock mutex that locked by another thread....");
		res = uthread_mutex_unlock(mutex);
		if (res == MUTEX_LOCKED)
			print_to_screen("OK\n");
		else print_to_screen("someting wrong\n");
		print_to_screen("thread 3 finished....\n");
	}
	/*for(i=0;i<10000000;i++);
	for(i=0;i<10000000;i++);
	for(i=0;i<10000000;i++);
	for(i=0;i<10000000;i++);
	for(i=0;i<10000000;i++);
	for(i=0;i<10000000;i++);
	for(i=0;i<10000000;i++);
	for(i=0;i<10000000;i++);
	for(i=0;i<10000000;i++);
	for(i=0;i<10000000;i++);
	for(i=0;i<10000000;i++);
	for(i=0;i<10000000;i++);
	for(i=0;i<10000000;i++);
	for(i=0;i<10000000;i++);
	for(i=0;i<10000000;i++);
	for(i=0;i<10000000;i++);
	for(i=0;i<10000000;i++);*/
	return 0;
}

void create_3_threads()
{
	int i=0;
	for (i=0;i<3;i++){
		arr[i] = uthread_create(start_routine,(void*)(i));
	}
	return;
}

int test2()
{
	msg("\n************Running test #13...******************\n");
	print_to_screen("thread 0 running.....\n");
	if (uthread_mutex_init(&mutex) != MUTEX_SUCCESS)
		print_to_screen("FAIL:INIT_MUTEX\n");
	print_to_screen("thread 0 create 3 threads.....\n");
	create_3_threads();
	print_to_screen("thread 0 yield the cpu ....\n");
	uthread_yield();
	print_to_screen("thread 0 continue waiting to other threads ....\n"); 
	int retval=5,res,i;
	for(i = 0; i < 3; i++) {
		res = uthread_join(arr[i],&retval);
	}
	
	if (uthread_mutex_destroy(mutex) != MUTEX_SUCCESS)
		print_to_screen("FAIL:DESTROY_MUTEX\n");
	print_to_screen("thread 0 finished ......\n");
	return 0;
}
